/*Copyright (C) 2013-2023 LZE*/
#include<bits/stdc++.h>
#define fo(x) freopen(#x".in", "r", stdin); freopen(#x".out", "w", stdout);
#define INF 0x7fffffff
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef const long long cll;
const int N = 100010;
const int M = 200010;
ll n, m, r, p;
ll a[N];
struct Edge {
    ll to, next;
    Edge() {}
} edge[M];
ll head[N], cnt = 0;
ll father[N], deep[N], size[N], hson[N], ndfn[N], nrnk[N];
ll top[N], dfn[N], rnk[N], tot = 0;
ll bot[N];
void add(cll &u, cll &v) {
    edge[++cnt].to = v;
    edge[cnt].next = head[u];
    head[u] = cnt;
}
ll baseInf(cll &step, cll &dep, cll &fat) {
//    cout << ":" << step << "; " << tot << "\n";
    ndfn[step] = ++tot;
    nrnk[tot] = step;
    deep[step] = dep;
    size[step] = 1;
    ll maxn = 0, hs = 0;
    for(ll i = head[step]; i; i = edge[i].next) {
        if(edge[i].to == fat) continue;
        size[step] += baseInf(edge[i].to, dep + 1, step);
        father[edge[i].to] = step;
        if(maxn < size[edge[i].to]) {
            maxn = size[edge[i].to];
            hs = edge[i].to;
        }
    }
    hson[step] = hs;
    return size[step];
}
ll treeDec(cll &step, cll &count, cll &fat) {
    // cout << " : " << step << endl;
    top[step] = count;
    dfn[step] = ++tot;
    rnk[tot] = step;
    ll bottom = tot;
    if(hson[step] == 0) return bot[step] = bottom;
    bottom = max(bottom, treeDec(hson[step], count, step));
    for(ll i = head[step]; i; i = edge[i].next) {
        if(edge[i].to == fat) continue;
        if(edge[i].to != hson[step]) {
            bottom = max(bottom, treeDec(edge[i].to, edge[i].to, step));
        }
    }
    return bot[step] = bottom;
}
ll nut[N];
class SegmentTree {
public:
    ll Tree[N << 2], tag[N << 2];
    SegmentTree() {}
    void build(cll &p, cll &l, cll &r) {
        if(l == r) {
            Tree[p] = nut[l];
            return;
        }
        ll mid = (l + r) >> 1;
        build(p << 1, l, mid);
        build(p << 1 | 1, mid + 1, r);
        Tree[p] = Tree[p << 1] + Tree[p << 1 | 1];
    }
    void pushdown(cll &p, cll &l, cll &r) {
        ll mid = (l + r) >> 1;
        tag[p << 1] += tag[p];
        tag[p << 1 | 1] += tag[p];
        Tree[p << 1] += (mid - l + 1) * tag[p];
        Tree[p << 1 | 1] += (r - mid) * tag[p];
        tag[p] = 0;
    }
    void update(cll &p, cll &l, cll &r, cll &L, cll &R, cll &val) {
        if(r < L || R < l) return;
        if(L <= l && r <= R) {
            Tree[p] += val * (r - l + 1);
            tag[p] += val;
            return;
        }
        ll mid = (l + r) >> 1;
        pushdown(p, l, r);
        if(R <= mid) update(p << 1, l, mid, L, R, val);
        else if(L > mid) update(p << 1 | 1, mid + 1, r, L, R, val);
        else {
            update(p << 1, l, mid, L, R, val);
            update(p << 1 | 1, mid + 1, r, L, R, val);
        }
        Tree[p] = Tree[p << 1] + Tree[p << 1 | 1];
    }
    ll query(cll &p, cll &l, cll &r, cll &L, cll &R) {
        if(r < L || R < l) return 0;
        if(L <= l && r <= R) { return Tree[p]; }
        ll mid = (l + r) >> 1;
        pushdown(p, l, r);
        if(R <= mid) return query(p << 1, l, mid, L, R);
        else if(L > mid) return query(p << 1 | 1, mid + 1, r, L, R);
        else {
            return query(p << 1, l, mid, L, R) +
            query(p << 1 | 1, mid + 1, r, L, R);
        }
    }
} link;
ll sumTreePath(ll u, ll v) {
    ll sum = 0;
    while(top[u] != top[v]) {
        if(deep[top[u]] < deep[top[v]]) swap(u, v);
        sum += link.query(1, 1, n, dfn[top[u]], dfn[u]);
        u = father[top[u]];
    }
    if(deep[u] > deep[v]) swap(u, v);
    sum += link.query(1, 1, n, dfn[u], dfn[v]);
    return sum;
}
void changeTreePath(ll u, ll v, cll &w) {
    while(top[u] != top[v]) {
        if(deep[top[u]] < deep[top[v]]) swap(u, v);
        link.update(1, 1, n, dfn[top[u]], dfn[u], w);
        u = father[top[u]];
    }
    if(deep[u] > deep[v]) swap(u, v);
    link.update(1, 1, n, dfn[u], dfn[v], w);
}
ll sumSubtree(ll u) {
    return link.query(1, 1, n, dfn[u], bot[u]);
}
void changeSubtree(ll u, cll &w) {
    // cout << ": " << dfn[u] << " " << bot[u] << endl;
    link.update(1, 1, n, dfn[u], bot[u], w);
}
int main() {
#ifdef LOCAL
    fo(debug_data)
#endif
    scanf("%lld%lld%lld%lld", &n, &m, &r, &p);
    for(ll i = 1; i <= n; i++) scanf("%lld", &a[i]);
    ll u, v;
    for(ll i = 1; i <= n - 1; i++) {
        scanf("%lld%lld", &u, &v);
        add(u, v);
        add(v, u);
    }
    baseInf(r, 1, 0);
    tot = 0;
    bot[r] = treeDec(r, r, 0);
    for(ll i = 1; i <= n; i++) { nut[i] = a[rnk[i]]; }
    // for(ll i = 1; i <= n; i++) cout << rnk[i] << " "; cout << endl;
    // for(ll i = 1; i <= n; i++) cout << dfn[i] << " "; cout << endl;
    link.build(1, 1, n);
    ll opt, x, y, z;
    // for(ll i = 1; i <= n; i++)
        // cout << link.query(1, 1, n, dfn[i], dfn[i]) << " ";
    // cout << endl;
    for(ll i = 1; i <= m; i++) {
        scanf("%lld%lld", &opt, &x);
        switch(opt) {
            case 1 : {
                scanf("%lld%lld", &y, &z);
                changeTreePath(x, y, z);
                break;
            }
            case 2 : {
                scanf("%lld", &y);
                printf("%lld\n", sumTreePath(x, y) % p);
                break;
            }
            case 3 : {
                scanf("%lld", &z);
                changeSubtree(x, z);
                break;
            }
            case 4 : {
                printf("%lld\n", sumSubtree(x) % p);
                break;
            }
        }
        // for(ll i = 1; i <= n; i++)
            // cout << link.query(1, 1, n, dfn[i], dfn[i]) << " ";
        // cout << endl;
    }
    return 0;
}